/**
 * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "unit_ecma_test.h"
#include "optimizer/ir/datatype.h"
#include "optimizer/ir/graph_cloner.h"
#include "optimizer/optimizations/cleanup.h"
#include "optimizer/optimizations/checks_elimination.h"

namespace ark::compiler {
class CheckEliminationEcmaTest : public AsmTest {
public:
    CheckEliminationEcmaTest() = default;

    // NOLINTBEGIN(readability-magic-numbers)
    template <bool IS_APPLIED>
    void TestAnyTypeCheck(AnyBaseType type1, profiling::AnyInputType inputType1, AnyBaseType type2,
                          profiling::AnyInputType inputType2)
    {
        auto graph = CreateGraphDynWithDefaultRuntime();
        GRAPH(graph)
        {
            PARAMETER(0, 0).any();

            BASIC_BLOCK(2, -1)
            {
                INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});
                INST(3, Opcode::AnyTypeCheck).any().AnyType(type1).Inputs(0, 2).AllowedInputType(inputType1);
                INST(4, Opcode::AnyTypeCheck).any().AnyType(type2).Inputs(0, 2).AllowedInputType(inputType2);
                INST(5, Opcode::ReturnVoid).v0id();
            }
        }

        Graph *graphOpt;
        if constexpr (IS_APPLIED) {
            graphOpt = CreateGraphDynWithDefaultRuntime();
            GRAPH(graphOpt)
            {
                PARAMETER(0, 0).any();

                BASIC_BLOCK(2, -1)
                {
                    INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});
                    INST(3, Opcode::AnyTypeCheck).any().AnyType(type1).Inputs(0, 2).AllowedInputType(inputType1);
                    INST(5, Opcode::ReturnVoid).v0id();
                }
            }

            EXPECT_TRUE(graph->RunPass<ChecksElimination>());
            EXPECT_TRUE(graph->RunPass<Cleanup>());
        } else {
            graphOpt = GraphCloner(graph, graph->GetAllocator(), graph->GetLocalAllocator()).CloneGraph();

            EXPECT_FALSE(graph->RunPass<ChecksElimination>());
        }
        GraphChecker(graph).Check();
        EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
    }
    // NOLINTEND(readability-magic-numbers)
};

// NOLINTBEGIN(readability-magic-numbers)
TEST_F(CheckEliminationEcmaTest, EliminateAnyTypeCheckAfterCastValueToAnyType)
{
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        PARAMETER(0, 0).any();
        CONSTANT(1, 1.0);

        BASIC_BLOCK(2, -1)
        {
            INST(10, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(1);
            INST(2, Opcode::SaveState).Inputs(0, 10).SrcVregs({0, 1});
            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(0, 2);
            INST(4, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(10, 2);
            INST(5, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(3);
            INST(6, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(4);
            INST(7, Opcode::Add).f64().Inputs(5, 6);
            INST(8, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(7);
            INST(9, Opcode::Return).any().Inputs(8);
        }
    }

    ASSERT_TRUE(graph->RunPass<ChecksElimination>());
    ASSERT_TRUE(graph->RunPass<Cleanup>());

    GraphChecker(graph).Check();

    auto graphOpt = CreateGraphDynWithDefaultRuntime();
    GRAPH(graphOpt)
    {
        PARAMETER(0, 0).any();
        CONSTANT(1, 1.0);

        BASIC_BLOCK(2, -1)
        {
            INST(10, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(1);
            INST(2, Opcode::SaveState).Inputs(0, 10).SrcVregs({0, 1});
            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(0, 2);
            INST(5, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(3);
            INST(6, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(10);
            INST(7, Opcode::Add).f64().Inputs(5, 6);
            INST(8, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(7);
            INST(9, Opcode::Return).any().Inputs(8);
        }
    }

    EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
}

TEST_F(CheckEliminationEcmaTest, EliminateAnyTypeCheckAfterCastIntToAnyType)
{
    for (auto intWasSeen : {true, false}) {
        auto graph = CreateGraphDynStubWithDefaultRuntime();
        GRAPH(graph)
        {
            PARAMETER(0, 0).s32();

            BASIC_BLOCK(2, -1)
            {
                INST(1, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(0);
                INST(5, Opcode::SaveState).Inputs(1).SrcVregs({0});
                INST(2, Opcode::AnyTypeCheck)
                    .any()
                    .AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE)
                    .Inputs(1, 5)
                    .IntegerWasSeen(intWasSeen);
                INST(3, Opcode::CastAnyTypeValue)
                    .f64()
                    .AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE)
                    .Inputs(2)
                    .IntegerWasSeen(intWasSeen);
                INST(4, Opcode::Return).f64().Inputs(3);
            }
        }

        auto graphOpt = CreateGraphDynStubWithDefaultRuntime();

        if (intWasSeen) {
            GRAPH(graphOpt)
            {
                PARAMETER(0, 0).s32();

                BASIC_BLOCK(2, -1)
                {
                    INST(1, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(0);
                    INST(3, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(1);
                    INST(4, Opcode::Return).f64().Inputs(3);
                }
            }
        } else {
            GRAPH(graphOpt)
            {
                PARAMETER(0, 0).s32();

                BASIC_BLOCK(2, -1)
                {
                    INST(1, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(0);
                    INST(5, Opcode::SaveState).Inputs(1).SrcVregs({0});
                    INST(6, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::ANY_TYPE_CHECK).Inputs(5);
                }
            }
        }

        EXPECT_TRUE(graph->RunPass<ChecksElimination>());
        graph->RunPass<Cleanup>();
        GraphChecker(graph).Check();
        EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
    }
}

TEST_F(CheckEliminationEcmaTest, EliminateDuplicateAnyTypeCheck)
{
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        PARAMETER(0, 0).any();

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});
            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(0, 2);
            INST(10, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(3, 2);
            INST(4, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(0, 2);
            INST(5, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(10);
            INST(6, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(4);
            INST(7, Opcode::Add).f64().Inputs(5, 6);
            INST(8, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(7);
            INST(9, Opcode::Return).any().Inputs(8);
        }
    }

    ASSERT_TRUE(graph->RunPass<ChecksElimination>());
    ASSERT_TRUE(graph->RunPass<Cleanup>());

    GraphChecker(graph).Check();

    auto graphOpt = CreateGraphDynWithDefaultRuntime();

    GRAPH(graphOpt)
    {
        PARAMETER(0, 0).any();

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});
            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(0, 2);
            INST(5, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(3);
            INST(6, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(3);
            INST(7, Opcode::Add).f64().Inputs(5, 6);
            INST(8, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(7);
            INST(9, Opcode::Return).any().Inputs(8);
        }
    }

    EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
}

TEST_F(CheckEliminationEcmaTest, EliminateDuplicateAnyTypeCheckCase3)
{
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        PARAMETER(0, 0).any();

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});

            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_STRING_TYPE).Inputs(0, 2);
            INST(4, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_OBJECT_TYPE).Inputs(0, 2);

            INST(5, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_STRING_TYPE).Inputs(3);
            INST(6, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_STRING_TYPE).Inputs(4);
            INST(7, Opcode::Add).f64().Inputs(5, 6);
            INST(8, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(7);
            INST(9, Opcode::Return).any().Inputs(8);
        }
    }

    ASSERT_TRUE(graph->RunPass<ChecksElimination>());
    ASSERT_TRUE(graph->RunPass<Cleanup>());

    GraphChecker(graph).Check();

    auto graphOpt = CreateGraphDynWithDefaultRuntime();

    GRAPH(graphOpt)
    {
        PARAMETER(0, 0).any();

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});

            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_STRING_TYPE).Inputs(0, 2);

            INST(5, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_STRING_TYPE).Inputs(3);
            INST(6, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_STRING_TYPE).Inputs(3);
            INST(7, Opcode::Add).f64().Inputs(5, 6);
            INST(8, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(7);
            INST(9, Opcode::Return).any().Inputs(8);
        }
    }

    EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
}

TEST_F(CheckEliminationEcmaTest, EliminateDuplicateAnyTypeCheckCase4)
{
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        PARAMETER(0, 0).any();

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});

            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(0, 2);
            INST(4, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(0, 2);

            INST(5, Opcode::CastAnyTypeValue).i32().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(3);
            INST(6, Opcode::CastAnyTypeValue).i32().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(4);
            INST(7, Opcode::Add).i32().Inputs(5, 6);
            INST(8, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(7);
            INST(9, Opcode::Return).any().Inputs(8);
        }
    }

    ASSERT_TRUE(graph->RunPass<ChecksElimination>());
    GraphChecker(graph).Check();

    auto graphOpt = CreateGraphDynWithDefaultRuntime();

    GRAPH(graphOpt)
    {
        PARAMETER(0, 0).any();

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});

            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(0, 2);

            INST(4, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::ANY_TYPE_CHECK).Inputs(2);
        }
    }

    EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
}

TEST_F(CheckEliminationEcmaTest, EliminateDuplicateAnyTypeCheckIntWasSeen)
{
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        PARAMETER(0, 0).any();
        PARAMETER(1, 1).any();

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});

            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(0, 2);
            INST(4, Opcode::AnyTypeCheck)
                .any()
                .AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE)
                .Inputs(0, 2)
                .IntegerWasSeen(true);

            INST(5, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(1, 2);
            INST(6, Opcode::AnyTypeCheck)
                .any()
                .AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE)
                .Inputs(1, 2)
                .IntegerWasSeen(true);

            INST(7, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(4);
            INST(8, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(6);
            INST(9, Opcode::Add).f64().Inputs(7, 8);
            INST(10, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(9);
            INST(11, Opcode::Return).any().Inputs(10);
        }
    }

    ASSERT_TRUE(graph->RunPass<ChecksElimination>());
    ASSERT_TRUE(graph->RunPass<Cleanup>());
    GraphChecker(graph).Check();

    auto graphOpt = CreateGraphDynWithDefaultRuntime();

    GRAPH(graphOpt)
    {
        PARAMETER(0, 0).any();
        PARAMETER(1, 1).any();

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});

            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(0, 2);
            INST(5, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(1, 2);

            INST(7, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(3);
            INST(8, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(5);
            INST(9, Opcode::Add).f64().Inputs(7, 8);
            INST(10, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(9);
            INST(11, Opcode::Return).any().Inputs(10);
        }
    }

    EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
}

TEST_F(CheckEliminationEcmaTest, NotEliminateAnyTypeCheckIntWasSeen)
{
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        PARAMETER(0, 0).any();
        PARAMETER(1, 1).any();

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});

            INST(3, Opcode::AnyTypeCheck)
                .any()
                .AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE)
                .Inputs(0, 2)
                .IntegerWasSeen(true);
            INST(4, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(0, 2);

            INST(5, Opcode::AnyTypeCheck)
                .any()
                .AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE)
                .Inputs(1, 2)
                .IntegerWasSeen(true);
            INST(6, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(1, 2);

            INST(7, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(3);
            INST(8, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(6);
            INST(9, Opcode::Add).f64().Inputs(7, 8);
            INST(10, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(9);
            INST(11, Opcode::Return).any().Inputs(10);
        }
    }

    auto graphOpt = GraphCloner(graph, graph->GetAllocator(), graph->GetLocalAllocator()).CloneGraph();

    ASSERT_FALSE(graph->RunPass<ChecksElimination>());
    GraphChecker(graph).Check();
    EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
}

TEST_F(CheckEliminationEcmaTest, TestAnyTypeCheckDoubleSpecialTypes)
{
    TestAnyTypeCheck<true>(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, profiling::AnyInputType::DEFAULT,
                           AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, profiling::AnyInputType::SPECIAL_INT);
    TestAnyTypeCheck<true>(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, profiling::AnyInputType::DEFAULT,
                           AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, profiling::AnyInputType::SPECIAL);
    TestAnyTypeCheck<true>(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, profiling::AnyInputType::SPECIAL,
                           AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, profiling::AnyInputType::SPECIAL_INT);
    TestAnyTypeCheck<true>(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, profiling::AnyInputType::SPECIAL,
                           AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, profiling::AnyInputType::SPECIAL);
    TestAnyTypeCheck<false>(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, profiling::AnyInputType::SPECIAL,
                            AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, profiling::AnyInputType::INTEGER);
    TestAnyTypeCheck<false>(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, profiling::AnyInputType::INTEGER,
                            AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, profiling::AnyInputType::DEFAULT);

    TestAnyTypeCheck<false>(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, profiling::AnyInputType::SPECIAL_INT,
                            AnyBaseType::ECMASCRIPT_INT_TYPE, profiling::AnyInputType::DEFAULT);
    TestAnyTypeCheck<true>(AnyBaseType::ECMASCRIPT_INT_TYPE, profiling::AnyInputType::DEFAULT,
                           AnyBaseType::ECMASCRIPT_DOUBLE_TYPE, profiling::AnyInputType::INTEGER);
}

TEST_F(CheckEliminationEcmaTest, TestAnyTypeCheckIntSpecialTypes)
{
    TestAnyTypeCheck<true>(AnyBaseType::ECMASCRIPT_INT_TYPE, profiling::AnyInputType::DEFAULT,
                           AnyBaseType::ECMASCRIPT_INT_TYPE, profiling::AnyInputType::SPECIAL);
    TestAnyTypeCheck<true>(AnyBaseType::ECMASCRIPT_INT_TYPE, profiling::AnyInputType::SPECIAL,
                           AnyBaseType::ECMASCRIPT_INT_TYPE, profiling::AnyInputType::SPECIAL);
    TestAnyTypeCheck<true>(AnyBaseType::ECMASCRIPT_INT_TYPE, profiling::AnyInputType::DEFAULT,
                           AnyBaseType::ECMASCRIPT_INT_TYPE, profiling::AnyInputType::DEFAULT);
    TestAnyTypeCheck<false>(AnyBaseType::ECMASCRIPT_INT_TYPE, profiling::AnyInputType::SPECIAL,
                            AnyBaseType::ECMASCRIPT_INT_TYPE, profiling::AnyInputType::DEFAULT);
}

TEST_F(CheckEliminationEcmaTest, NotEliminateAnyTypeCheck)
{
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        PARAMETER(0, 0).any();
        PARAMETER(10, 1).any();
        PARAMETER(11, 2).any();

        BASIC_BLOCK(2, 3, 4)
        {
            INST(12, Opcode::CompareAnyType).b().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(11);
            INST(13, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_EQ).Imm(0).Inputs(12);
        }
        BASIC_BLOCK(3, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0, 10).SrcVregs({0, 1});
            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(0, 2);
            INST(4, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(10, 2);
            INST(5, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(3);
            INST(6, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(4);
            INST(7, Opcode::Add).f64().Inputs(5, 6);
            INST(8, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(7);
            INST(9, Opcode::Return).any().Inputs(8);
        }
        BASIC_BLOCK(4, -1)
        {
            INST(22, Opcode::SaveState).Inputs(0, 10).SrcVregs({0, 1});
            INST(23, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(0, 22);
            INST(24, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(10, 22);
            INST(25, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(23);
            INST(26, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(24);
            INST(27, Opcode::Sub).f64().Inputs(25, 26);
            INST(28, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(27);
            INST(29, Opcode::Return).any().Inputs(28);
        }
    }

    auto graphOpt = GraphCloner(graph, graph->GetAllocator(), graph->GetLocalAllocator()).CloneGraph();

    ASSERT_FALSE(graph->RunPass<ChecksElimination>());
    ASSERT_FALSE(graph->RunPass<Cleanup>());

    GraphChecker(graph).Check();

    EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
}

TEST_F(CheckEliminationEcmaTest, MoveAnyTypeCheckFromLoop)
{
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        PARAMETER(0, 0).any();
        CONSTANT(5, 1);
        BASIC_BLOCK(2, 3)
        {
            INST(1, Opcode::SaveState).Inputs(0).SrcVregs({0}).Pc(10U);
            INST(7, Opcode::Intrinsic).v0id().Inputs({{DataType::NO_TYPE, 1}}).Pc(10U);
        }
        BASIC_BLOCK(3, 3, 4)
        {
            INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0}).Pc(20U);
            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(0, 2).Pc(20U);
            INST(6, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(5).Pc(20U);
        }
        BASIC_BLOCK(4, -1)
        {
            INST(4, Opcode::ReturnVoid).v0id().Pc(30U);
        }
    }

    ASSERT_TRUE(graph->RunPass<ChecksElimination>());
    ASSERT_TRUE(graph->RunPass<Cleanup>());
    GraphChecker(graph).Check();

    auto &saveState = INS(1);
    Inst *check = nullptr;
    for (auto userIt = saveState.GetUsers().begin(); userIt != saveState.GetUsers().end();) {
        if (userIt->GetInst()->GetOpcode() == Opcode::AnyTypeCheck) {
            check = userIt->GetInst();
            break;
        }
    }
    ASSERT_NE(check, nullptr);
    ASSERT_EQ(check->GetPc(), saveState.GetPc());

    auto graphOpt = CreateGraphDynWithDefaultRuntime();

    GRAPH(graphOpt)
    {
        PARAMETER(0, 0).any();
        CONSTANT(5, 1);
        BASIC_BLOCK(2, 3)
        {
            INST(1, Opcode::SaveState).Inputs(0).SrcVregs({0});
            INST(30, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(0, 1);
            INST(7, Opcode::Intrinsic).v0id().Inputs({{DataType::NO_TYPE, 1}});
        }
        BASIC_BLOCK(3, 3, 4)
        {
            INST(6, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(5);
        }
        BASIC_BLOCK(4, -1)
        {
            INST(4, Opcode::ReturnVoid).v0id();
        }
    }

    EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
}

TEST_F(CheckEliminationEcmaTest, MoveAnyTypeCheckFromLoop2)
{
    // not applied, AnyTypeCheck not moved, because it isn't dominate on all back edges.
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        PARAMETER(0, 0).any();
        CONSTANT(5, 1);
        BASIC_BLOCK(2, 4, 5)
        {
            INST(6, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(5);
        }
        BASIC_BLOCK(4, 2, 6)
        {
            INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});
            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(0, 2);
            INST(7, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(5);
        }
        BASIC_BLOCK(5, 2, 6)
        {
            INST(8, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(5);
        }
        BASIC_BLOCK(6, -1)
        {
            INST(4, Opcode::ReturnVoid).v0id();
        }
    }

    auto graphOpt = GraphCloner(graph, graph->GetAllocator(), graph->GetLocalAllocator()).CloneGraph();

    ASSERT_FALSE(graph->RunPass<ChecksElimination>());
    GraphChecker(graph).Check();
    EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
}

TEST_F(CheckEliminationEcmaTest, EliminateAnyTypeCheckWithUndefinedType)
{
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        PARAMETER(0, 0).any();

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0).SrcVregs({0});

            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::UNDEFINED_TYPE).Inputs(0, 2);

            INST(4, Opcode::Return).any().Inputs(3);
        }
    }

    ASSERT_TRUE(graph->RunPass<ChecksElimination>());
    ASSERT_TRUE(graph->RunPass<Cleanup>());
    GraphChecker(graph).Check();

    auto graphOpt = CreateGraphDynWithDefaultRuntime();

    GRAPH(graphOpt)
    {
        PARAMETER(0, 0).any();

        BASIC_BLOCK(2, -1)
        {
            INST(4, Opcode::Return).any().Inputs(0);
        }
    }

    EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
}

// NOTE(kaskov) Not shue that we can eliminate duplicate LoadObject and HclassCheck
TEST_F(CheckEliminationEcmaTest, EliminateDuplicateHclassCheck)
{
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        PARAMETER(0, 0).any();
        PARAMETER(1, 1).any();
        CONSTANT(10, 0xa).any();

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1});

            INST(11, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE).Inputs(0, 2);
            INST(12, Opcode::LoadObject)
                .ref()
                .TypeId(TypeIdMixin::MEM_DYN_CLASS_ID)
                .ObjectType(ObjectType::MEM_DYN_CLASS)
                .Inputs(11);
            INST(13, Opcode::LoadObject)
                .ref()
                .TypeId(TypeIdMixin::MEM_DYN_HCLASS_ID)
                .ObjectType(ObjectType::MEM_DYN_HCLASS)
                .Inputs(12);
            INST(14, Opcode::HclassCheck).any().Inputs(13, 2).SetChecks(HclassChecks::ALL_CHECKS);
            INST(5, Opcode::CallDynamic).any().InputsAutoType(11, 10, 10, 1, 2);

            INST(15, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE).Inputs(0, 2);
            INST(16, Opcode::LoadObject)
                .ref()
                .TypeId(TypeIdMixin::MEM_DYN_CLASS_ID)
                .ObjectType(ObjectType::MEM_DYN_CLASS)
                .Inputs(15);
            INST(17, Opcode::LoadObject)
                .ref()
                .TypeId(TypeIdMixin::MEM_DYN_HCLASS_ID)
                .ObjectType(ObjectType::MEM_DYN_HCLASS)
                .Inputs(16);
            INST(18, Opcode::HclassCheck).any().Inputs(17, 2).SetChecks(HclassChecks::ALL_CHECKS);
            INST(8, Opcode::CallDynamic).any().InputsAutoType(15, 10, 10, 1, 2);

            INST(9, Opcode::Return).any().Inputs(8);
        }
    }

    ASSERT_TRUE(graph->RunPass<ChecksElimination>());
    ASSERT_TRUE(graph->RunPass<Cleanup>());
    GraphChecker(graph).Check();

    auto graphOpt = CreateGraphDynWithDefaultRuntime();

    GRAPH(graphOpt)
    {
        PARAMETER(0, 0).any();
        PARAMETER(1, 1).any();
        CONSTANT(10, 0xa).any();

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1});

            INST(11, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE).Inputs(0, 2);
            INST(12, Opcode::LoadObject)
                .ref()
                .TypeId(TypeIdMixin::MEM_DYN_CLASS_ID)
                .ObjectType(ObjectType::MEM_DYN_CLASS)
                .Inputs(11);
            INST(13, Opcode::LoadObject)
                .ref()
                .TypeId(TypeIdMixin::MEM_DYN_HCLASS_ID)
                .ObjectType(ObjectType::MEM_DYN_HCLASS)
                .Inputs(12);
            INST(14, Opcode::HclassCheck).any().Inputs(13, 2).SetChecks(HclassChecks::ALL_CHECKS);

            INST(5, Opcode::CallDynamic).any().InputsAutoType(11, 10, 10, 1, 2);
            INST(8, Opcode::CallDynamic).any().InputsAutoType(11, 10, 10, 1, 2);

            INST(9, Opcode::Return).any().Inputs(8);
        }
    }

    EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
}

TEST_F(CheckEliminationEcmaTest, EliminateHclassCheckInlined)
{
    auto method = reinterpret_cast<RuntimeInterface::MethodPtr>(1);
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        PARAMETER(0, 0).any();
        PARAMETER(1, 1).any();
        CONSTANT(10, 0xa).any();

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1});

            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE).Inputs(0, 2);
            INST(4, Opcode::LoadObject)
                .ref()
                .TypeId(TypeIdMixin::MEM_DYN_CLASS_ID)
                .ObjectType(ObjectType::MEM_DYN_CLASS)
                .Inputs(3);
            INST(11, Opcode::LoadObject)
                .ref()
                .TypeId(TypeIdMixin::MEM_DYN_HCLASS_ID)
                .ObjectType(ObjectType::MEM_DYN_HCLASS)
                .Inputs(4);
            INST(12, Opcode::HclassCheck).any().Inputs(11, 2).SetChecks(HclassChecks::ALL_CHECKS);
            INST(13, Opcode::LoadImmediate)
                .ptr()
                .Class(method)
                .ObjectTypeLoadImm(LoadImmediateInst::ObjectType::METHOD);
            INST(14, Opcode::LoadObject)
                .ptr()
                .TypeId(TypeIdMixin::MEM_DYN_METHOD_ID)
                .ObjectType(ObjectType::MEM_DYN_METHOD)
                .Inputs(3);
            INST(15, Opcode::Compare).SrcType(DataType::POINTER).CC(CC_NE).b().Inputs(14, 13);
            INST(16, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::INLINE_DYN).Inputs(15, 2);

            INST(5, Opcode::CallDynamic).any().Inlined().InputsAutoType(3, 10, 10, 1, 2);
            INST(6, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1}).Caller(5);
            // do something to prevent cleanup of call/return inlined
            INST(7, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(1, 6);
            INST(8, Opcode::ReturnInlined).Inputs(2);
            INST(9, Opcode::Return).any().Inputs(7);
        }
    }

    ASSERT_TRUE(graph->RunPass<ChecksElimination>());
    GraphChecker(graph).Check();

    auto graphOpt = CreateGraphDynWithDefaultRuntime();

    GRAPH(graphOpt)
    {
        PARAMETER(0, 0).any();
        PARAMETER(1, 1).any();
        CONSTANT(10, 0xa).any();

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1});

            INST(3, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE).Inputs(0, 2);
            INST(4, Opcode::LoadObject)
                .ref()
                .TypeId(TypeIdMixin::MEM_DYN_CLASS_ID)
                .ObjectType(ObjectType::MEM_DYN_CLASS)
                .Inputs(3);
            INST(11, Opcode::LoadObject)
                .ref()
                .TypeId(TypeIdMixin::MEM_DYN_HCLASS_ID)
                .ObjectType(ObjectType::MEM_DYN_HCLASS)
                .Inputs(4);
            INST(12, Opcode::HclassCheck).any().Inputs(11, 2).SetChecks(HclassChecks::IS_FUNCTION);
            INST(13, Opcode::LoadImmediate)
                .ptr()
                .Class(method)
                .ObjectTypeLoadImm(LoadImmediateInst::ObjectType::METHOD);
            INST(14, Opcode::LoadObject)
                .ptr()
                .TypeId(TypeIdMixin::MEM_DYN_METHOD_ID)
                .ObjectType(ObjectType::MEM_DYN_METHOD)
                .Inputs(3);
            INST(15, Opcode::Compare).SrcType(DataType::POINTER).CC(CC_NE).b().Inputs(14, 13);
            INST(16, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::INLINE_DYN).Inputs(15, 2);

            INST(5, Opcode::CallDynamic).any().Inlined().InputsAutoType(3, 10, 10, 1, 2);
            INST(6, Opcode::SaveState).Inputs(0, 1).SrcVregs({0, 1}).Caller(5);
            // do something to prevent cleanup of call/return inlined
            INST(7, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_INT_TYPE).Inputs(1, 6);
            INST(8, Opcode::ReturnInlined).Inputs(2);
            INST(9, Opcode::Return).any().Inputs(7);
        }
    }
    EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
}

// NOTE(kaskov) To deal with the correctness of the HclassCheck
// Not shue that we can move LoadObject and HclassCheck from loop
TEST_F(CheckEliminationEcmaTest, MoveHclassCheckFromLoop)
{
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        CONSTANT(0, 0);  // initial
        CONSTANT(1, 1);  // increment
        CONSTANT(2, 10);

        BASIC_BLOCK(2, 3, 5)
        {
            INST(3, Opcode::SaveState).Inputs(0, 1, 2).SrcVregs({0, 1, 2});
            INST(4, Opcode::Intrinsic)
                .any()
                .IntrinsicId(compiler::RuntimeInterface::IntrinsicId::INTRINSIC_LDLEXENV_DYN)
                .Inputs({{compiler::DataType::NO_TYPE, 3}});
            INST(5, Opcode::Intrinsic)
                .any()
                .IntrinsicId(compiler::RuntimeInterface::IntrinsicId::INTRINSIC_DEFINEFUNC_DYN)
                .Inputs({{compiler::DataType::ANY, 4}, {compiler::DataType::NO_TYPE, 3}});
            INST(20, Opcode::SaveStateDeoptimize).Inputs(0, 1, 2, 4, 5).SrcVregs({0, 1, 2, 4, 5});
            INST(6, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0, 2);  // 0 < 10
            INST(7, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(6);
        }
        BASIC_BLOCK(3, 3, 5)
        {
            INST(8, Opcode::Phi).s32().Inputs(0, 13);
            INST(9, Opcode::SaveState).Inputs(0, 1, 2, 4, 5).SrcVregs({0, 1, 2, 4, 5});

            INST(10, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE).Inputs(5, 9);

            INST(17, Opcode::LoadObject)
                .ref()
                .TypeId(TypeIdMixin::MEM_DYN_CLASS_ID)
                .ObjectType(ObjectType::MEM_DYN_CLASS)
                .Inputs(10);
            INST(18, Opcode::LoadObject)
                .ref()
                .TypeId(TypeIdMixin::MEM_DYN_HCLASS_ID)
                .ObjectType(ObjectType::MEM_DYN_HCLASS)
                .Inputs(17);
            INST(11, Opcode::HclassCheck).any().Inputs(18, 9).SetChecks(HclassChecks::ALL_CHECKS);

            INST(12, Opcode::CallDynamic).any().InputsAutoType(10, 2, 2, 8, 9);

            INST(13, Opcode::Add).s32().Inputs(8, 1);               // i++
            INST(14, Opcode::Compare).CC(CC_LT).b().Inputs(13, 2);  // i < 10
            INST(15, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(14);
        }
        BASIC_BLOCK(5, 1)
        {
            INST(16, Opcode::ReturnVoid).v0id();
        }
    }

    ASSERT_TRUE(graph->RunPass<ChecksElimination>());
    GraphChecker(graph).Check();
    auto graphOpt = CreateGraphDynWithDefaultRuntime();

    GRAPH(graphOpt)
    {
        CONSTANT(0, 0);  // initial
        CONSTANT(1, 1);  // increment
        CONSTANT(2, 10);

        BASIC_BLOCK(2, 3, 5)
        {
            INST(3, Opcode::SaveState).Inputs(0, 1, 2).SrcVregs({0, 1, 2});
            INST(4, Opcode::Intrinsic)
                .any()
                .IntrinsicId(compiler::RuntimeInterface::IntrinsicId::INTRINSIC_LDLEXENV_DYN)
                .Inputs({{compiler::DataType::NO_TYPE, 3}});
            INST(5, Opcode::Intrinsic)
                .any()
                .IntrinsicId(compiler::RuntimeInterface::IntrinsicId::INTRINSIC_DEFINEFUNC_DYN)
                .Inputs({{compiler::DataType::ANY, 4}, {compiler::DataType::NO_TYPE, 3}});
            INST(20, Opcode::SaveStateDeoptimize).Inputs(0, 1, 2, 4, 5).SrcVregs({0, 1, 2, 4, 5});
            INST(10, Opcode::AnyTypeCheck).any().AnyType(AnyBaseType::ECMASCRIPT_HEAP_OBJECT_TYPE).Inputs(5, 20);
            INST(6, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0, 2);  // 0 < 10
            INST(7, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(6);
        }
        BASIC_BLOCK(3, 3, 5)
        {
            INST(8, Opcode::Phi).s32().Inputs(0, 13);
            INST(9, Opcode::SaveState).Inputs(0, 1, 2, 4, 5).SrcVregs({0, 1, 2, 4, 5});

            INST(17, Opcode::LoadObject)
                .ref()
                .TypeId(TypeIdMixin::MEM_DYN_CLASS_ID)
                .ObjectType(ObjectType::MEM_DYN_CLASS)
                .Inputs(10);
            INST(18, Opcode::LoadObject)
                .ref()
                .TypeId(TypeIdMixin::MEM_DYN_HCLASS_ID)
                .ObjectType(ObjectType::MEM_DYN_HCLASS)
                .Inputs(17);
            INST(11, Opcode::HclassCheck).any().Inputs(18, 9).SetChecks(HclassChecks::ALL_CHECKS);

            INST(12, Opcode::CallDynamic).any().InputsAutoType(10, 2, 2, 8, 9);

            INST(13, Opcode::Add).s32().Inputs(8, 1);               // i++
            INST(14, Opcode::Compare).CC(CC_LT).b().Inputs(13, 2);  // i < 10
            INST(15, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(14);
        }
        BASIC_BLOCK(5, 1)
        {
            INST(16, Opcode::ReturnVoid).v0id();
        }
    }
    ASSERT_TRUE(GraphComparator().Compare(graph, graphOpt));
}
// NOLINTEND(readability-magic-numbers)

}  // namespace ark::compiler
